require 'DictServiceDriver.rb'

class DictServiceHelper

  DEFAULT_MATCHES_COUNT = 5

  def self.synchronise_dictionaries
    DictServiceHelper.fetch_dictionaries(true)
  end

  def self.synchronise_strategies
    DictServiceHelper.fetch_strategies
  end

  def self.match(word, strategy, view_all = false)
    soap = DictService::DictServiceSoap.new
    m = DictService::Match.new(word.text, strategy.strategy_id)
    
    begin
      response = soap.match(m)
    rescue SOAP::FaultError
      response = nil
    end

    matches = response ? response.matchResult : []
    matching_words = DictServiceHelper.matching_words(matches)
    view_all ? matching_words : matching_words[0, DEFAULT_MATCHES_COUNT]
  end

  def self.get_dictionary_info(dictionary)
    soap = DictService::DictServiceSoap.new

    begin
      response = soap.dictionaryInfo(DictService::DictionaryInfo.new(dictionary.dictionary_id))
    rescue SOAP::FaultError
      response = nil
    end
    
    dictionary.info = response && response.dictionaryInfoResult ? response.dictionaryInfoResult : ''
    dictionary
  end

  def self.define(word)
    soap = DictService::DictServiceSoap.new
    define = DictService::Define.new(word.text)

    begin
      response = soap.define(define)
    rescue SOAP::FaultError
      response = nil
    end

    definitions = response && response.defineResult ? response.defineResult.definitions : []
    DictServiceHelper.add_definitions(definitions)
  end

  def self.define_in_dictionary(word, dictionary)
    soap = DictService::DictServiceSoap.new
    define_in_dic = DictService::DefineInDict.new(dictionary.dictionary_id, word.text)
    
    begin
      response = soap.defineInDict(define_in_dic)
    rescue SOAP::FaultError
      response = nil
    end

    definitions = response && response.defineInDictResult ? response.defineInDictResult.definitions : []
    DictServiceHelper.add_definitions(definitions)
  end

  private

  def self.fetch_dictionaries(fetch_all = true)
    soap = DictService::DictServiceSoap.new
    
    begin
      response = soap.dictionaryList(DictService::DictionaryList.new)
    rescue SOAP::FaultError
      response = nil
    end

    dictionaries = response ? response.dictionaryListResult : []

    if fetch_all
      begin
        response = soap.dictionaryListExtended(DictService::DictionaryListExtended.new)
      rescue SOAP::FaultError
        response = nil
      end

      dictionaries.concat(response.dictionaryListExtendedResult) if response
    end

    DictServiceHelper.add_dictionaries(dictionaries)
  end

  def self.fetch_strategies
    soap = DictService::DictServiceSoap.new

    begin
      response = soap.strategyList(DictService::StrategyList.new)
    rescue SOAP::FaultError
      response = nil
    end

    strategies = response ? response.strategyListResult : []

    DictServiceHelper.add_strategies(strategies)
  end

  def self.add_dictionaries(dictionaries)
    for dictionary in dictionaries
      unless Dictionary.exists?(:dictionary_id => dictionary.id)
        Dictionary.create(:name => dictionary.name, :dictionary_id => dictionary.id)
      end
    end
  end

  def self.add_strategies(strategies)
    for strategy in strategies
      unless Strategy.exists?(:strategy_id => strategy.id)
        Strategy.create(:name => strategy.description, :strategy_id => strategy.id)
      end
    end
  end

  def self.add_definitions(definitions)
    definitions.each_with_index do |definition, position|
     unless WordDefinition.find(:first,
                                  :conditions => ['words.text = ? AND dictionaries.dictionary_id = ? AND position = ?',
                                                  definition.word.downcase, definition.dictionary.id, position],
                                  :include => [:word, :dictionary])
        word = Word.find_by_text(definition.word.downcase)
        dictionary = Dictionary.find_or_create_by_dictionary_id(definition.dictionary.id)

        WordDefinition.create(:word => word, :dictionary => dictionary,
                              :position => position, :text => definition.wordDefinition)
      end
    end
  end

  def self.matching_words(matches)
    matches_by_word = matches.index_by {|match| match.word.downcase}
    words_matching = []

    matches_by_word.each_pair do |word, match|
      m = Match.new
      m.word = Word.find_or_create_by_text(word)
      m.dictionary = Dictionary.find_or_create_by_dictionary_id(match.dictionaryId)
      words_matching << m
    end

    words_matching
  end

end
